/* @(#)
 *
 * Project:  jekun-shop
 *
 * Modify Information:
 * =============================================================================
 *   Author           Date           Description
 *   ------------     ----------     --------------------------------------------
 *   Roger.Luo        2014年5月5日        first release
 *
 *
 * Copyright Notice:
 * =============================================================================
 *       Copyright 2014 FANKE Software, Inc. All rights reserved.
 *
 *       This software is the confidential and proprietary information of
 *       GUANGZHOU FANKE INTERNET TECHNOLOGY CO.,LTD ("Confidential Information").
 *       You shall not disclose such Confidential Information and shall use it
 *       only in accordance with the terms of the license agreement you entered
 *       into with FANKE.
 *
 * Warning:
 * =============================================================================
 *
 */
package cn.jekun.shop.web.service;

import java.sql.Types;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import net.sf.json.JSONObject;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;

import cn.jekun.component.base.exceptions.BusinessException;
import cn.jekun.component.base.utils.SqlUtis;
import cn.jekun.component.base.validator.annotation.Mobile;
import cn.jekun.component.core.Constants;
import cn.jekun.component.core.bean.gen.ErpOrders;
import cn.jekun.component.core.bean.gen.ErpTxnSeq;
import cn.jekun.component.core.bean.gen.RsUser;
import cn.jekun.component.core.service.ComponentCoreService;
import cn.jekun.component.core.service.gen.ErpOrdersService;
import cn.jekun.component.pay.base.BasePay;
import cn.jekun.component.core.service.gen.ErpTxnSeqService;
import cn.jekun.component.shop.service.OrderService;
import cn.jekun.component.shop.service.ThirdBusinessService;


@Service(UnionPayService.BEAN_NAME)
public class UnionPayService extends ComponentCoreService {
	
	//记录日志信息
	private static Logger logger=Logger.getLogger(UnionPayService.class);
	
	public static final String BEAN_NAME = "cn.jekun.shop.web.service.UnionPayService";
	
	public static String [] PARAMS={"MerId","OrderNo","OrderAmount","CurrCode","BankCode","OrderType","nOrderType","CallBackUrl","ResultMode","Reserved01","Reserved02","SourceText","PKey","EntryMode","ret"};	
	public String SignedMsg = "";
	@Resource(name=ErpOrdersService.BEAN_NAME)
	ErpOrdersService orpOrdersService;	
	@Resource(name=ThirdBusinessService.BEAN_NAME)
	ThirdBusinessService thirdBusinessService;
	@Resource(name=ErpTxnSeqService.BEAN_NAME)
	ErpTxnSeqService erpTxnSeqService;
	@Resource(name=OrderService.BEAN_NAME)
	OrderService orderService;
		
	/**
	 * 响应通知
	 * @param request
	 */
	public JSONObject notify(HttpServletRequest request){
		
		logger.info("********************** WebPay UnionPayService 接收银联参数开始 **********************");
		String txn_State="1";
		JSONObject jsonObject = new JSONObject();
		logger.info("UnionPayService  Notify begin ");
		String userId="system";
		//接收银联在线返回数据
		//----------------------------------------------------------------------------------------
		String EncodeMsg;
		String SignMsg;
		EncodeMsg = request.getParameter("EncodeMsg");
		SignMsg = request.getParameter("SignMsg");
		logger.info("银联支付返回的原始参数信息：EncodeMsg："+EncodeMsg+",SignMsg:"+SignMsg);
		
		BasePay unionPay=BasePay.CreateNewWebPay("02", "", "");
		unionPay.setParameter("EncodeMsg", EncodeMsg);
		unionPay.setParameter("SignMsg", SignMsg);
		jsonObject=unionPay.NotifyFrontInfo();
		
		//取出支付工具中的返回数据域
		String OrderNo, PayNo, PayAmount, CurrCode, SystemSSN, RespCode, SettDate, Reserved01, Reserved02;
		
		String code =jsonObject.getString("code");//商户订单号
		
		if(code.equals("1")){
			OrderNo = jsonObject.getString("OrderNo");//商户订单号
			PayNo = jsonObject.getString("PayNo");//支付单号
			PayAmount = jsonObject.getString("PayAmount");//支付金额
			CurrCode = jsonObject.getString("CurrCode");//货币代码
			SystemSSN = jsonObject.getString("SystemSSN");//系统参考号
			RespCode = jsonObject.getString("RespCode");//响应码
			SettDate = jsonObject.getString("SettDate");//清算日期
			Reserved01 = jsonObject.getString("Reserved01");//保留域1
			Reserved02 = jsonObject.getString("Reserved02");//保留域2
			
			String returnText="OrderNo="+OrderNo+"&PayNo="+PayNo+"&PayAmount="
					+PayAmount+"&CurrCode="+CurrCode+"&SystemSSN="+SystemSSN+"&RespCode="+RespCode+"&SettDate="+SettDate
					+"&Reserved01="+Reserved01+"&Reserved02="+Reserved02;
			logger.info(returnText);
			logger.info("********************** WebPay UnionPayService 参数信息处理结束**********************");
			if (null != RespCode && RespCode.equals("00")) {//开始记录返回的交易流水信息
	    		txn_State=Constants.TXN_STATE.TXN_O2;// 交易处理成功
			}
			
			//先根据订单号查询订单信息是否存在，然后再保存交易信息
	    	Map formTxnMap = new HashMap();
			formTxnMap.put(ErpOrders.COL_ORDER_ID, OrderNo);
			SqlUtis.prepareSql(formTxnMap,
					SqlUtis.getSQL(formTxnMap, "a."
					+ ErpOrders.COL_ORDER_ID,Types.VARCHAR,SqlUtis.EQ));
			ErpOrders orders = orpOrdersService.one(formTxnMap);
	    	/**
	    	 * 订单支付成功
	    	 */
	    	if(orders.getOrderStatusId().equals("1")){
	    		jsonObject.put("orderAmount",((int) ((orders.getTotalAmount())*100)+""));
				return executeRerutn(jsonObject);	        		
	    	}else if(orders.getOrderStatusId().equals(Constants.ERP_ORDER_STATUS.PAY)){//订单为待支付状态，说明支付后没有更新结果，须更新订单状态及记录交易流水
	    		//******************************************************
				//开始记录返回的交易流水信息
				String returnId =this.saveTxnInfo(OrderNo,Constants.TRANS_TYPE.GO_PAY,Constants.ONLINE_PAYMENT.UNION_PAY,Constants.MAINFRAME_TYPE.FRONT_PAY,PayNo,txn_State,RespCode,SystemSSN,Constants.PAY_CHANNEL.PAY_WEB);
				if(returnId == null){
					return executeRerutnFail(jsonObject);
				}else{
//					String temp = OrderNo.substring(0, 2);
//					if(temp.equals("FK")){
//						orderService.payConfirmOrderByPayNo(userId, OrderNo, Constants.ONLINE_PAYMENT.UNION_PAY, PayNo);//保存银联返回的订单支付号，后续退货及撤消需要用到
//					}else{
						orderService.payConfirmOrder(userId, OrderNo, Constants.ONLINE_PAYMENT.UNION_PAY, PayNo,Constants.PAY_CHANNEL.PAY_WEB);//保存银联返回的订单支付号，后续退货及撤消需要用到
						thirdBusinessService.callThirdService(OrderNo, userId);
//					}
					jsonObject.put("orderAmount", ((int) ((orders.getTotalAmount())*100)+""));
					return executeRerutn(jsonObject);
				}
	    	}else{
	    		return executeRerutnFail(jsonObject);
	    	}
		}else{
			return executeRerutnFail(jsonObject);
		}
	}
	
	/**
	 * 获取银联异步消息通知
	 * @param request
	 */
	public JSONObject notifyWebPayResult(HttpServletRequest request){
    	
		logger.info("********************UnionPayService  notifyWebPayResult begin***********************");
		JSONObject jsonObject = new JSONObject();
		String userId="system";
    	//获取银联POST过来异步通知信息
		//----------------------------------------------------------------------------------------
		String EncodeMsg;
		String SignMsg;
		EncodeMsg = request.getParameter("EncodeMsg");
		SignMsg = request.getParameter("SignMsg");
		logger.info("获取到的银联支付异步消息：EncodeMsg："+EncodeMsg+",&&   SignMsg:"+SignMsg);
				
		String OrderNo, PayNo, PayAmount, CurrCode, SystemSSN, RespCode, SettDate, Reserved01, Reserved02;
		boolean ret;
    	String txn_State="1";
    	BasePay unionPay=BasePay.CreateNewWebPay("02", "", "");
		unionPay.setParameter("EncodeMsg", EncodeMsg);
		unionPay.setParameter("SignMsg", SignMsg);
		jsonObject=unionPay.NotifyBackInfo();
		
		OrderNo = jsonObject.getString("OrderNo");//商户订单号
		PayNo = jsonObject.getString("PayNo");//支付单号
		PayAmount = jsonObject.getString("PayAmount");//支付金额
		CurrCode = jsonObject.getString("CurrCode");//货币代码
		SystemSSN = jsonObject.getString("SystemSSN");//系统参考号
		RespCode = jsonObject.getString("RespCode");//响应码
		SettDate = jsonObject.getString("SettDate");//清算日期
		Reserved01 = jsonObject.getString("Reserved01");//保留域1
		Reserved02 = jsonObject.getString("Reserved02");//保留域2
		
		String returnText="OrderNo="+OrderNo+"&PayNo="+PayNo+"&PayAmount="
				+PayAmount+"&CurrCode="+CurrCode+"&SystemSSN="+SystemSSN+"&RespCode="+RespCode+"&SettDate="+SettDate
				+"&Reserved01="+Reserved01+"&Reserved02="+Reserved02;
		logger.info(returnText);
		logger.info("********************** UnionPayService notifyWebPayResult 参数信息处理结束**********************");
//		String temp = OrderNo.substring(0, 2);
		if (null != RespCode && RespCode.equals("00")) {		//开始记录返回的交易流水信息
    		txn_State=Constants.TXN_STATE.TXN_O2;// 交易处理成功
		}
		
		//先根据订单号查询订单信息是否存在，然后再保存交易信息
    	Map formTxnMap = new HashMap();
		formTxnMap.put(ErpOrders.COL_ORDER_ID, OrderNo);
		SqlUtis.prepareSql(formTxnMap,SqlUtis.getSQL(formTxnMap, "a."+ ErpOrders.COL_ORDER_ID,Types.VARCHAR,SqlUtis.EQ));
		ErpOrders orders = orpOrdersService.one(formTxnMap);
		
    	if(orders.getOrderStatusId().equals("1")){//订单支付成功
    		logger.info("success");
    	}else if(orders.getOrderStatusId().equals(Constants.ERP_ORDER_STATUS.PAY)){//订单为待支付状态，说明没有发起支付，或者是支付后没有更新结果，须更新订单状态及记录交易流水
    		//******************************************************
			//开始记录返回的交易流水信息
			String returnId =this.saveTxnInfo(OrderNo,Constants.TRANS_TYPE.GO_PAY,Constants.ONLINE_PAYMENT.UNION_PAY,Constants.MAINFRAME_TYPE.BACK_PAY,SystemSSN,txn_State,RespCode,Reserved01,Constants.PAY_CHANNEL.PAY_WEB);
			logger.info("success");
//			if(temp.equals("FK")){
//				orderService.payConfirmOrderByPayNo(userId, OrderNo, Constants.ONLINE_PAYMENT.UNION_PAY, SystemSSN);
//			}else{
				orderService.payConfirmOrder(userId, OrderNo, Constants.ONLINE_PAYMENT.UNION_PAY, PayNo,Constants.PAY_CHANNEL.PAY_WEB);
				thirdBusinessService.callThirdService(OrderNo, userId);
//			}
    	}
    	logger.info("********************** UnionPayService notifyWebPayResult End**********************");
    	return this.executeRerutn(jsonObject);
	}
	
	 /**
	 * 查询订单状态
	 * 
	 *	vendorid     ：开放商户ID(3位，由银联分配)    193                     
	 *	userid       ：银联在线商家后台系统登录帐号   test                   
	 *	pwd          ：银联在线商家后台系统登录密码    password                     
	 *	paysuc       ：0返回支付失败订单，1返回支付成功订单，2或空返回所有订单#
	 *  shoppingtime ：上次返回的最后订单时间   2013-08-06 可以为空                           
	 *  starttime    ：订单查询开始时间         2013-08-06 01:20:00     可以为空                       
	 *  endtime      ：订单查询结束时间           2013-08-06 11:20:00     可以为空  
	 *	orderNo      ：订单号   可为空       
	 *  注意：如果后面的三个时间要填shoppingtime 或者是starttime 和endtime ，那个默认为查询当天的订单数据，
	 *  如果填写开始时间和结束时间，查询范围不能超出1天。只能查询２８天内的数据。
	 */
	public JSONObject queryPayResult(HttpServletRequest request){
		
		logger.info("UnionPayService queryPayResult Begin *********************");
		JSONObject jsonObject = new JSONObject();
		String orderId = request.getParameter("orderId");//需要查询的订单号
		String starttime = request.getParameter("starttime");//需要查询的开始时间
		String endtime = request.getParameter("endtime");//需要查询的结束时间
		
		this.saveTxnInfo(orderId,Constants.TRANS_TYPE.QUERY,Constants.ONLINE_PAYMENT.UNION_PAY,Constants.MAINFRAME_TYPE.UNION_PAY,"","0","","",Constants.PAY_CHANNEL.PAY_WEB);
		BasePay unionPay=BasePay.CreateNewWebPay("02", "", "");
		unionPay.setParameter("OrderId", orderId);
		unionPay.setParameter("starttime", starttime);
		unionPay.setParameter("endtime", endtime);
		jsonObject=unionPay.Query();
		this.saveTxnInfo(orderId,Constants.TRANS_TYPE.QUERY,Constants.ONLINE_PAYMENT.UNION_PAY,Constants.MAINFRAME_TYPE.UNION_PAY,"","1","","",Constants.PAY_CHANNEL.PAY_WEB);
		return executeRerutn(jsonObject);
	}
	
	/**
	 * 银联退货接口
	 * @param orderNo
	 * @param refundAmount
	 * @return
	 */
	public JSONObject Refund(@ErpOrders.AnnoOrderId String orderNo,@ErpOrders.AnnoTotalAmount String refundAmount){
		
		logger.info("UnionPayService Refund Begin *********************");
		JSONObject jsonObject = new JSONObject();
		String userId="system";
		
		//******************************************************
		Map formQueryTxnMap = new HashMap();
		formQueryTxnMap.put(ErpTxnSeq.COL_ORDER_ID, orderNo);
		formQueryTxnMap.put(ErpTxnSeq.COL_TXN_STATE, "1");
		SqlUtis.prepareSql(formQueryTxnMap,
				SqlUtis.getSQL(formQueryTxnMap, "a."
				+ ErpTxnSeq.COL_ORDER_ID,Types.VARCHAR,SqlUtis.EQ),
				SqlUtis.getSQL(formQueryTxnMap, "a."
						+ ErpTxnSeq.COL_TXN_STATE,Types.VARCHAR,SqlUtis.EQ));
		ErpTxnSeq txnOldSeq = erpTxnSeqService.one(formQueryTxnMap);
		
		String strShoppingDate=txnOldSeq.getInTxnDt();
		String strPayNo = txnOldSeq.getExtTxnSeqId();// 网付通生成的支付流水号
		String CardNo = "";// 保留域1
		String Explain = "test2";// 保留域1
		
		try{
			logger.info("记录交易流 水，开始发起退货交易。");
			this.saveTxnInfo(orderNo,Constants.TRANS_TYPE.PAY_BACK,Constants.ONLINE_PAYMENT.UNION_PAY,Constants.MAINFRAME_TYPE.UNION_PAY,"","0","","",Constants.PAY_CHANNEL.PAY_WEB);
			BasePay unionPay=BasePay.CreateNewWebPay("02",orderNo, refundAmount);
			
			unionPay.setParameter("GneteDate", strShoppingDate);
			unionPay.setParameter("OrderNo", orderNo);
			unionPay.setParameter("PayNo", strPayNo);
			unionPay.setParameter("ReturnAmount", refundAmount);
			unionPay.setParameter("CardNo", CardNo);
			unionPay.setParameter("Explain", Explain);
			
			jsonObject=unionPay.Refund();
			String respCode=jsonObject.getString("RespCode");
			logger.info("记录交易流 水，退货交易完成。");
			this.saveTxnInfo(orderNo,Constants.TRANS_TYPE.PAY_BACK,Constants.ONLINE_PAYMENT.UNION_PAY,Constants.MAINFRAME_TYPE.UNION_PAY,"","1",respCode,"",Constants.PAY_CHANNEL.PAY_WEB);
			//修改订单状态，将订单状态改为已退货
			orderService.refund(userId, orderNo);
			return jsonObject;
			
		}catch(Exception exc){
			logger.info(exc.getMessage());;
			jsonObject.put("code", "0");
			jsonObject.put("message", "退款失败");
			return jsonObject;
		}
	}
	
	/**
	 * 生成银联支付所需参数
	 * @param order 订单号
	 * @param clientIp 客户端IP
 	 * @param userId 用户ID
	 * @param mobile 手机号码
	 * @return
	 */
	public JSONObject genUnionPayParams(@ErpOrders.AnnoOrderId String order,String clientIp,@RsUser.AnnoUserId String userId,@Mobile(message="手机号码格式不正确") String mobile){
		
		logger.info(" ********************* UnionPayService pay Begin *********************");
		JSONObject jsonObject = new JSONObject();
		if (StringUtils.isBlank(order)) {
			throw new BusinessException(Constants.ERRORS.VALIDATE_ERROR_CODE,"订单号不能为空");
		}
		if (StringUtils.isBlank(clientIp)) {
			throw new BusinessException(Constants.ERRORS.VALIDATE_ERROR_CODE,"客户端IP不能为空");
		}
		Date myDate = new Date();	
		Map formMap = new HashMap();
		formMap.put(ErpOrders.COL_ORDER_ID, order);//1：根据order去数据库查询order_id=order的订单判断其是否存在
		SqlUtis.prepareSql(formMap,SqlUtis.getSQL(formMap, "a."+ ErpOrders.COL_ORDER_ID,Types.VARCHAR,SqlUtis.EQ));
		
		ErpOrders erpOrder = orpOrdersService.one(formMap);
		if(erpOrder == null){
			throw new BusinessException(Constants.ERRORS.VALIDATE_ERROR_CODE,"此订单不存在");
		}
		//2：判断订单的订单状态是否为待付款order_status_id=5
		if(!erpOrder.getOrderStatusId().equals("5")){
			throw new BusinessException(Constants.ERRORS.VALIDATE_ERROR_CODE,"此订单为非待付款状态,不允许支付");
		}
		//3:判断订单的付款请求时间是否为空
		if(erpOrder.getPayReqTime() != null){
			throw new BusinessException(Constants.ERRORS.VALIDATE_ERROR_CODE,"此订单已发送支付请求");
		}
		//4：判断订单的付款确认时间是否为空
		if(erpOrder.getPayTime() != null){
			throw new BusinessException(Constants.ERRORS.VALIDATE_ERROR_CODE,"此订单已经支付完成了");
		}
		//测试后台通知消息地址：http://183.60.181.99/shop/shopweb/Transaction/notifyWebPayBackResult.do
		String OrderAmount =""+erpOrder.getTotalAmount(); //订单金额，格式：元.角分""+(int) ((erpOrder.getTotalAmount())*100)
	
		BasePay unionPay=BasePay.CreateNewWebPay("02", order, OrderAmount);
		jsonObject=unionPay.GenerateForm();
		logger.info("UnionPayService 报文生成结束  *********************");
		
		String returnId =this.saveTxnInfo(order,Constants.TRANS_TYPE.GO_PAY,Constants.ONLINE_PAYMENT.UNION_PAY,Constants.MAINFRAME_TYPE.UNION_PAY,"","0","","",Constants.PAY_CHANNEL.PAY_WEB);
		logger.info("UnionPayService 交易日志保存结束  *********************");
		if(returnId == null){
			return this.executeRerutnFail(jsonObject);
		}
		else{
			return this.executeRerutn(jsonObject);
		}
	}
	
	/**
	 * 保存交易流水信息
	 * @param orderId 订单编号
	 * @param transType 交易类型 00支付，01撤消（退款）
	 * @param payType 支付方式 01 翼支付，02银联支付
	 * @param mType 主机类型 ，主机类型 ，00－银联支付 ;01－翼支付；02－积分支付；03－前台主机;04－后台主机，05－APP，06－网站， 07－终端
	 * @param extTxnId 外部交易流水号
	 * @param txnState 交易状态
	 */
	public String saveTxnInfo(
			@ErpOrders.AnnoOrderId String orderId,
			@ErpTxnSeq.AnnoTxnType String transType,
			@ErpTxnSeq.AnnoPayType String payType,
			@ErpTxnSeq.AnnoTrnType String mType,
			@ErpTxnSeq.AnnoExtTxnSeqId String extTxnId,
			@ErpTxnSeq.AnnoTxnState String txnState,
			@ErpTxnSeq.AnnoResCode String resCode,
			@ErpTxnSeq.AnnoResDesc String resDesc,
			@ErpTxnSeq.AnnoPayChannelId String payChannel){
		
		//开始根据订单编号得到订单信息
		if(orderId==null ||orderId.isEmpty()){
			return "";
		}
		if(resCode==null){
			resCode="";
		}
		if(resDesc==null){
			resCode="";
		}
		Map formTxnMap = new HashMap();
		formTxnMap.put(ErpOrders.COL_ORDER_ID, orderId);
		SqlUtis.prepareSql(formTxnMap,
				SqlUtis.getSQL(formTxnMap, "a."
				+ ErpOrders.COL_ORDER_ID,Types.VARCHAR,SqlUtis.EQ));
		ErpOrders erpOrder = orpOrdersService.one(formTxnMap);
		
		Map tempMap = new HashMap();
		ErpTxnSeq txnSeq = new ErpTxnSeq();
		txnSeq.setTxnType(transType);//交易类型 00支付;01撤消(退款);
		txnSeq.setPayType(payType);//支付方式:01翼支付02银联支付
		txnSeq.setTrnType(mType);//mType 主机类型 ，主机类型 ，00－银联支付 ;01－翼支付；02－积分支付；03－前台主机;04－后台主机，05－APP，06－网站， 07－终端
		txnSeq.setPayChannelId(payChannel);
		txnSeq.setOrderId(orderId);//订单号
		txnSeq.setTxnDtTm((new SimpleDateFormat("yyyyMMddHHmmss")).format(erpOrder.getCreateTime()));//订单日期时间
		txnSeq.setTxnAmt(String.valueOf((int) ((erpOrder.getTotalAmount())*100)));//订单金额
		txnSeq.setInTxnDt(new SimpleDateFormat("yyyyMMddHHmmss").format(erpOrder.getCreateTime()));//内部交易日期
		txnSeq.setExtTxnSeqId(extTxnId);//外部交易流水号，发起交易时为空
		txnSeq.setBonusValue(0.00);//积分数量
		txnSeq.setFeeAmt("0");//手续费
		txnSeq.setTxnState(txnState);//交易状态（发起支付请求）
		txnSeq.setResCode(resCode);
		txnSeq.setResDesc(resDesc);
		txnSeq.setCreateOper("system");
		txnSeq.setDelFlag("0");//记录有效标识：0：未删除；1：已删除
		tempMap.put("erpTxnSeq", txnSeq);
		return erpTxnSeqService.insert(tempMap).toString();
	}
}
